<?xml version="1.0" encoding="UTF-8"?>
<!--
   - xstlib2xsl.xsl
   - Preprocess tag library to XSLT
   -
   - Copyright (c) 2011 Erik Hennum. All Rights Reserved.
   -
   - Licensed under the Apache License, Version 2.0 (the "License");
   - you may not use this file except in compliance with the License.
   - You may obtain a copy of the License at
   -
   - http://www.apache.org/licenses/LICENSE-2.0
   -
   - Unless required by applicable law or agreed to in writing, software
   - distributed under the License is distributed on an "AS IS" BASIS,
   - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   - See the License for the specific language governing permissions and
   - limitations under the License.
   -
   - The use of the Apache License does not indicate that this work is
   - associated with the Apache Software Foundation.
   -
  -->
<xsl:stylesheet version="2.0"
    xmlns:xsl = "http://www.w3.org/1999/XSL/Transform"
    xmlns:osl = "file:///www.w3.org/1999/XSL/Transform"
    xmlns:fn  = "http://www.w3.org/2005/xpath-functions"
    xmlns:xs  = "http://www.w3.org/2001/XMLSchema"
    xmlns:xst = "http://code.google.com/p/xstag/ns/2011/"
    >

<xsl:import href="xst2xslutil.xsl"/>

<xsl:namespace-alias stylesheet-prefix="osl" result-prefix="xsl"/>

<xsl:template match="/xst:taglib">
  <xsl:variable name="libroot" select="."/>

  <xsl:if test="fn:exists(@for) and fn:not(fn:lower-case(@for) = ('xstag','xslt'))">
    <xsl:message terminate="yes">
      <xsl:text>Cannot preprocess tag library for: </xsl:text>
      <xsl:value-of select="@for"/>
    </xsl:message>
  </xsl:if>

  <xsl:variable name="namespaces" as="element()*">
    <xsl:for-each select="fn:in-scope-prefixes($libroot)">
      <namespace prefix="{.}" uri="{fn:namespace-uri-for-prefix(., $libroot)}"/>
    </xsl:for-each>
  </xsl:variable>

  <xsl:variable name="imports" as="element(xst:import)*"
          select="$libroot//xst:import[fn:empty(@for) or @for = ('xstag', 'xslt')]"/>

  <xsl:variable name="taglibs" as="element(xst:taglib)*"
          select="xst:import-taglibs($imports[fn:empty(@for) or @for eq 'xstag'])"/>

  <xsl:variable name="tagdefs" as="element(xst:tag)*"
          select="xst:extract-tagdefs((.|$taglibs),$namespaces)"/>

  <xsl:variable name="handler-tags" as="element(xst:tag)*"
        select="$tagdefs[fn:exists(
            xst:param[fn:starts-with(fn:normalize-space(@as),'handler(')]
            )]"/>

  <xsl:variable name="handler-calls" as="element()*"
        select="if (fn:exists($handler-tags))
            then //xst:call[@tag=$handler-tags/@imp-qname]
            else ()"/>

  <xsl:text>
</xsl:text>
  <xsl:comment>GENERATED by xstlib2xsl.xsl - please do not edit</xsl:comment>
  <xsl:text>
</xsl:text>
  <osl:stylesheet version="2.0">
    <xsl:for-each select="$namespaces">
      <xsl:namespace name="{@prefix}" select="@uri"/>
    </xsl:for-each>
    <xsl:text>
</xsl:text>

    <xsl:for-each select="$imports">
      <xsl:variable name="href">
        <xsl:choose>
        <xsl:when test="@for eq 'xslt'">
          <xsl:value-of
              select="@href"/>
        </xsl:when>
        <xsl:otherwise>
          <xsl:value-of
              select="fn:concat(fn:replace(@href,'^(.*?)\.[^.]+$','$1'),'.xsl')"/>
        </xsl:otherwise>
        </xsl:choose>
      </xsl:variable>
      <osl:import href="{$href}"/>
      <xsl:text>
</xsl:text>
    </xsl:for-each>

    <xsl:apply-templates select="node()" mode="xst:convert">
      <xsl:with-param name="tagdefs" select="$tagdefs"/>
    </xsl:apply-templates>

    <xsl:apply-templates select="$handler-calls" mode="xst:handler-call">
      <xsl:with-param name="tagdefs" select="$tagdefs"/>
    </xsl:apply-templates>
  </osl:stylesheet>
  <xsl:text>
</xsl:text>
</xsl:template>

<xsl:template match="xst:tag" mode="xst:convert">
  <xsl:param name="tagdefs" as="element(xst:tag)*"/>

  <xsl:variable name="tag-name" as="xs:string?" select="fn:string(@name)"/>
  <xsl:variable name="tag-uri"  as="xs:string?"
        select="fn:string(fn:namespace-uri-for-prefix(
            fn:substring-before($tag-name,':'),/xst:taglib))"/>

  <xsl:variable name="all-params"       as="element(xst:param)*"
        select="xst:param"/>
  <xsl:variable name="handlers"         as="element(xst:param)*"
        select="$all-params[fn:starts-with(fn:normalize-space(@as),'handler(')]"/>
  <xsl:variable name="default-handlers" as="element(xst:param)*"
        select="$handlers[fn:exists(* | text()[fn:matches(.,'\S')])]"/>
  <xsl:variable name="empty-handlers"   as="element(xst:param)*"
        select="$handlers except $default-handlers"/>
  <xsl:variable name="params"           as="element(xst:param)*"
        select="$all-params except $handlers"/>

  <xsl:variable name="body"             as="node()*"
        select="if (fn:exists($all-params))
            then $all-params[fn:last()]/following-sibling::node()
            else node()"/>

  <xsl:if test="fn:count($all-params[@implicit eq 'true']) gt 1">
    <xsl:message>
      <xsl:value-of select="$tag-name"/>
      <xsl:text> has more than one implicit parameter: </xsl:text>
      <xsl:value-of select="fn:string-join($all-params[@implicit eq 'true'], ', ')"/>
    </xsl:message>
  </xsl:if>

  <xsl:if test="fn:exists($default-handlers)">
    <osl:variable name="{$tag-name}-DEFAULT-CALL" as="element(xst:caller)">
      <xst:caller tag="{$tag-name}" call="0" module-uri="{$tag-uri}">
        <xsl:apply-templates select="$default-handlers" mode="xst:handler-match"/>
      </xst:caller>
    </osl:variable>
  </xsl:if>

  <osl:template>
    <xsl:copy-of select="@*"/>

    <xsl:apply-templates select="$params" mode="xst:convert">
      <xsl:with-param name="tagdefs" select="$tagdefs"/>
    </xsl:apply-templates>

    <xsl:if test="$handlers">
      <osl:param name="xst:caller" as="element(xst:caller)?"/>

      <xsl:apply-templates select="$default-handlers" mode="xst:default-handler-variable">
        <xsl:with-param name="tag-name" select="$tag-name"/>
      </xsl:apply-templates>
      <xsl:apply-templates select="$empty-handlers"   mode="xst:empty-handler-variable"/>
    </xsl:if>

    <xsl:apply-templates select="$body" mode="xst:convert">
      <xsl:with-param name="tagdefs" select="$tagdefs"/>
    </xsl:apply-templates>
  </osl:template>

  <xsl:apply-templates select="$default-handlers" mode="xst:handler-template">
    <xsl:with-param name="tagdefs"  select="$tagdefs"/>
    <xsl:with-param name="tag-name" select="$tag-name"/>
    <xsl:with-param name="tag-uri"  select="$tag-uri"/>
  </xsl:apply-templates>
</xsl:template>

<xsl:template match="xst:param" mode="xst:handler-match">
  <xsl:variable name="handler-name" as="xs:string?" select="fn:string(@name)"/>

  <xst:handler name="{$handler-name}"/>
</xsl:template>

<xsl:template match="xst:param" mode="xst:default-handler-variable">
  <xsl:param name="tag-name" as="xs:string?"/>

  <xsl:variable name="handler-name" as="xs:string?" select="fn:string(@name)"/>

  <osl:variable
        name="{$handler-name}"
        as="element(xst:handler)?"
        select="($xst:caller/xst:handler[@name eq '{$handler-name}'],
            ${$tag-name}-DEFAULT-CALL/xst:handler[@name eq '{$handler-name}']
            )[1]"/>
</xsl:template>

<xsl:template match="xst:param" mode="xst:empty-handler-variable">
  <xsl:variable name="handler-name" as="xs:string?" select="fn:string(@name)"/>

  <osl:variable
        name="{$handler-name}"
        as="element(xst:handler)?"
        select="$xst:caller/xst:handler[@name eq '{$handler-name}']"/>
</xsl:template>

<xsl:template match="xst:call[@tag]" mode="xst:convert">
  <xsl:param name="tagdefs" as="element(xst:tag)*"/>

  <xsl:variable name="tag-name" as="xs:string?" select="fn:string(@tag)"/>

  <xsl:variable name="called-tag" as="element(xst:tag)?"
          select="$tagdefs[@imp-qname eq $tag-name]"/>

  <xsl:choose>
  <xsl:when test="fn:exists($called-tag)">
    <xsl:variable name="all-paramdefs" as="element(xst:param)*"
            select="$called-tag/xst:param"/>
    <xsl:variable name="handlerdefs"   as="element(xst:param)*"
            select="$all-paramdefs[fn:starts-with(fn:normalize-space(@as),'handler(')]"/>
    <xsl:variable name="paramdefs"     as="element(xst:param)*"
            select="$all-paramdefs except $handlerdefs"/>

    <xsl:variable name="params" as="element(xst:with-param)*"
            select="xst:with-param"/>
    <xsl:variable name="handlers" as="element(xst:with-handler)*"
            select="xst:with-handler"/>

    <xsl:variable name="confused-params" as="element(xst:with-param)*"
            select="$params[@name=$handlerdefs/@name]"/>
    <xsl:variable name="confused-handlers" as="element(xst:with-handler)*"
            select="$handlers[@name=$paramdefs/@name]"/>

    <xsl:variable name="invalid-params" as="element(xst:with-param)*"
            select="($params except $confused-params)
                [not(@name=$paramdefs/@name)]"/>
    <xsl:variable name="invalid-handlers" as="element(xst:with-handler)*"
            select="($handlers except $confused-handlers)
                [not(@name=$handlerdefs/@name)]"/>

    <xsl:variable name="required-params" as="element(xst:param)*"
            select="$paramdefs[fn:exists(@as) and
                fn:not(fn:matches(@as,'[?*]\s*$'))]"/>
    <xsl:variable name="required-handlers" as="element(xst:param)*"
            select="$handlerdefs[fn:exists(@as) and
                fn:not(fn:matches(@as,'[?*]\s*$'))]"/>
    <xsl:variable name="missing-params" as="element(xst:param)*"
            select="$required-params[not(@name=$params/@name)]"/>
    <xsl:variable name="missing-handlers" as="element(xst:param)*"
            select="$required-handlers[not(@name=$handlers/@name)]"/>

    <xsl:choose>
    <xsl:when test="fn:empty($confused-params) and
            fn:empty($confused-handlers) and
            fn:empty($invalid-params) and
            fn:empty($invalid-handlers) and
            fn:empty($missing-params) and
            fn:empty($missing-handlers)">
      <osl:call-template name="{$called-tag/@name}">
        <xsl:apply-templates select="$params" mode="xst:call-param">
          <xsl:with-param name="tagdefs"   select="$tagdefs"/>
          <xsl:with-param name="paramdefs" select="$paramdefs"/>
        </xsl:apply-templates>

        <xsl:if test="fn:exists($handlers)">
          <xsl:apply-templates select="." mode="xst:caller-param">
            <xsl:with-param name="tag-name"           select="$tag-name"/>
            <xsl:with-param name="called-tag"         select="$called-tag"/>
            <xsl:with-param name="handler-names"
                select="$handlers/fn:string(@name)"/>
            <xsl:with-param name="handler-containers" select="$handlers"/>
            <xsl:with-param name="is-call"            select="fn:true()"/>
          </xsl:apply-templates>
        </xsl:if>
      </osl:call-template>
    </xsl:when>
    <xsl:otherwise>
      <xsl:if test="fn:exists($confused-params)">
        <xsl:message terminate="yes">
          <xsl:value-of select="$tag-name"/>
          <xsl:text> tag passes param values for the handlers: </xsl:text>
          <xsl:value-of select="fn:string-join($confused-params/@name,', ')"/>
        </xsl:message>
      </xsl:if>
      <xsl:if test="fn:exists($confused-handlers)">
        <xsl:message terminate="yes">
          <xsl:value-of select="$tag-name"/>
          <xsl:text> tag passes handler values for the params: </xsl:text>
          <xsl:value-of select="fn:string-join($confused-handlers/@name,', ')"/>
        </xsl:message>
      </xsl:if>
      <xsl:if test="fn:exists($invalid-params)">
        <xsl:message terminate="yes">
          <xsl:value-of select="$tag-name"/>
          <xsl:text> tag passes values for non-existent parameters: </xsl:text>
          <xsl:value-of select="fn:string-join($invalid-params/@name,', ')"/>
        </xsl:message>
      </xsl:if>
      <xsl:if test="fn:exists($invalid-handlers)">
        <xsl:message terminate="yes">
          <xsl:value-of select="$tag-name"/>
          <xsl:text> tag passes values for non-existent handlers: </xsl:text>
          <xsl:value-of select="fn:string-join($invalid-handlers/@name,', ')"/>
        </xsl:message>
      </xsl:if>
      <xsl:if test="fn:exists($missing-params)">
        <xsl:message terminate="yes">
          <xsl:value-of select="$tag-name"/>
          <xsl:text> tag does not pass a value for the required parameters: </xsl:text>
          <xsl:value-of select="fn:string-join($missing-params/@name,', ')"/>
        </xsl:message>
      </xsl:if>
      <xsl:if test="fn:exists($missing-handlers)">
        <xsl:message terminate="yes">
          <xsl:value-of select="$tag-name"/>
          <xsl:text> tag does not pass a value for the required handlers: </xsl:text>
          <xsl:value-of select="fn:string-join($missing-handlers/@name,', ')"/>
        </xsl:message>
      </xsl:if>
    </xsl:otherwise>
    </xsl:choose>
  </xsl:when>
  <xsl:otherwise>
    <xsl:message terminate="yes">
      <xsl:value-of select="$tag-name"/>
      <xsl:text> tag does not exist in the tag library</xsl:text>
    </xsl:message>
  </xsl:otherwise>
  </xsl:choose>
</xsl:template>

<xsl:template match="xst:with-param" mode="xst:call-param">
  <xsl:param name="tagdefs"   as="element(xst:tag)*"/>
  <xsl:param name="paramdefs" as="element(xst:param)*"/>

  <xsl:variable name="param-name" as="xs:string?" select="@name"/>

  <xsl:variable name="called-param" as="element(xst:param)?"
          select="$paramdefs[@name eq $param-name]"/>

  <xsl:choose>
  <xsl:when test="fn:exists($called-param)">
    <xsl:variable name="param-select" as="attribute()?"
            select="@select"/>

    <xsl:variable name="param-type" as="attribute()?"
            select="$called-param/@as"/>

    <osl:with-param>
      <xsl:copy-of select="$called-param/@name | $param-type"/>

      <xsl:choose>
      <xsl:when test="fn:exists($param-select)">
        <xsl:attribute name="select"
              select="xst:cast-as($param-select, $param-type)"/>
      </xsl:when>
      <xsl:otherwise>
        <xsl:apply-templates select="node()" mode="xst:convert">
          <xsl:with-param name="tagdefs" select="$tagdefs"/>
        </xsl:apply-templates>
      </xsl:otherwise>
      </xsl:choose>
    </osl:with-param>
  </xsl:when>
  <xsl:otherwise>
    <xsl:message terminate="yes">
      <xsl:value-of select="$param-name"/>
      <xsl:text> call parameter does not exist in the tag definition</xsl:text>
    </xsl:message>
  </xsl:otherwise>
  </xsl:choose>
</xsl:template>

<xsl:template match="xst:call[@tag]" mode="xst:handler-call">
  <xsl:param name="tagdefs" as="element(xst:tag)*"/>

  <xsl:variable name="tag-name" as="xs:string?" select="fn:string(@tag)"/>

  <xsl:variable name="called-tag" as="element(xst:tag)?"
          select="$tagdefs[@imp-qname eq $tag-name]"/>

  <xsl:variable name="call-count" as="xs:integer"
        select="xst:count-calls(., $tag-name)"/>

  <xsl:variable name="handlerdefs" as="element(xst:param)*"
        select="$called-tag/xst:param[
            fn:starts-with(fn:normalize-space(@as),'handler(')]"/>

  <xsl:for-each select="xst:with-handler">
    <xsl:variable name="handler-name" as="xs:string" select="fn:string(@name)"/>

    <xsl:apply-templates select="." mode="xst:handlerdef">
      <xsl:with-param name="tagdefs"      select="$tagdefs"/>
      <xsl:with-param name="tag-name"     select="$tag-name"/>
      <xsl:with-param name="call-count"   select="$call-count"/>
      <xsl:with-param name="handlerdefs"  select="$handlerdefs"/>
      <xsl:with-param name="handler-name" select="$handler-name"/>
      <xsl:with-param name="is-call"      select="fn:true()"/>
    </xsl:apply-templates>
  </xsl:for-each>
</xsl:template>

<xsl:template match="xst:call[@handler]" mode="xst:convert">
  <xsl:param name="tagdefs" as="element(xst:tag)*"/>

  <xsl:variable name="handler-name" as="xs:string?"
        select="fn:substring-after(@handler,'$')"/>

  <xsl:variable name="handlerdef" as="element(xst:param)?"
        select="ancestor::xst:tag[1]/xst:param[@name eq $handler-name]"/>

  <xsl:variable name="param-list" as="xs:string*"
        select="xst:parse-handler-params($handlerdef/@as)"/>

  <osl:apply-templates select="${$handler-name}" mode="xst:handle">
    <xsl:apply-templates select="xst:with-param" mode="xst:handler-param">
      <xsl:with-param name="tagdefs"    select="$tagdefs"/>
      <xsl:with-param name="param-list" select="$param-list"/>
    </xsl:apply-templates>
  </osl:apply-templates>
</xsl:template>

<xsl:template match="xst:call[@name]" mode="xst:convert">
  <xsl:param name="tagdefs" as="element(xst:tag)*"/>

  <osl:call-template>
    <xsl:copy-of select="@*"/>

    <xsl:for-each select="xst:with-param">
      <osl:with-param>
        <xsl:copy-of select="@*"/>

        <xsl:apply-templates select="node()" mode="xst:convert">
          <xsl:with-param name="tagdefs" select="$tagdefs"/>
        </xsl:apply-templates>

      </osl:with-param>
    </xsl:for-each>

  </osl:call-template>
</xsl:template>

<xsl:template match="xst:with-param" mode="xst:handler-param">
  <xsl:param name="tagdefs"    as="element(xst:tag)*"/>
  <xsl:param name="param-list" as="xs:string*"/>

  <xsl:variable name="param-name" as="xs:string?" select="fn:normalize-space(@name)"/>

  <xsl:variable name="param-type" as="xs:string?"
        select="if (fn:exists(@as))
            then fn:normalize-space(@as)
            else if (fn:exists($param-list))
            then $param-list[fn:index-of($param-list, $param-name) + 1]
            else ''"/>

  <osl:with-param>
    <xsl:copy-of select="@name|@select"/>

    <xsl:if test="fn:string-length($param-type) gt 0">
      <xsl:attribute name="as" select="$param-type"/>
    </xsl:if>

    <xsl:apply-templates select="node()" mode="xst:convert">
      <xsl:with-param name="tagdefs" select="$tagdefs"/>
    </xsl:apply-templates>
  </osl:with-param>
</xsl:template>

<xsl:template match="xst:param" mode="xst:handler-template">
  <xsl:param name="tagdefs"  as="element(xst:tag)*"/>
  <xsl:param name="tag-name" as="xs:string?"/>
  <xsl:param name="tag-uri"  as="xs:string?"/>

  <xsl:variable name="handler-name" as="xs:string?" select="fn:string(@name)"/>

  <osl:template match="xst:handler[
            @name          eq '{$handler-name}' and
            ../@tag        eq '{$tag-name}'     and
            ../@call       eq '0'               and
            ../@module-uri eq '{$tag-uri}']"
        mode="xst:handle">

    <xsl:apply-templates select="." mode="xst:handler-signature"/>

    <xsl:apply-templates select="node()" mode="xst:convert">
      <xsl:with-param name="tagdefs" select="$tagdefs"/>
    </xsl:apply-templates>
  </osl:template>
</xsl:template>

<xsl:template match="xst:content" mode="xst:convert">
  <xsl:param name="tagdefs" as="element(xst:tag)*"/>

  <osl:sequence>
    <xsl:apply-templates select="@select" mode="xst:convert">
      <xsl:with-param name="tagdefs" select="$tagdefs"/>
    </xsl:apply-templates>
  </osl:sequence>
</xsl:template>

<xsl:template match="xst:for-each[fn:exists(@name)]" mode="xst:convert">
  <xsl:param name="tagdefs" as="element(xst:tag)*"/>

  <xsl:variable name="item-name" select="fn:string(@name)"/>
  <xsl:variable name="sort"      select="xst:sort"/>

  <osl:for-each>
    <xsl:apply-templates select="@* except (@name|@at)" mode="xst:convert">
      <xsl:with-param name="tagdefs" select="$tagdefs"/>
    </xsl:apply-templates>
    <xsl:if test="fn:exists($sort)">
      <xsl:apply-templates select="$sort/preceding-sibling::node()" mode="xst:convert">
        <xsl:with-param name="tagdefs" select="$tagdefs"/>
      </xsl:apply-templates>
      <osl:sort>
        <!-- should be okay if a pseudo-reference isn't embedded in a string -->
        <xsl:attribute name="select" select="fn:replace(
                fn:concat(' ',$sort/@select,' '),
                fn:concat('\$',$item-name,'(\C)'),
                '.$1',
                's')"/>
      </osl:sort>
    </xsl:if>
    <osl:variable name="{$item-name}" select="."/>
    <xsl:if test="fn:exists(@at)">
      <osl:variable name="{fn:string(@at)}" select="fn:position()"/>
    </xsl:if>
    <xsl:choose>
    <xsl:when test="fn:exists($sort)">
      <xsl:apply-templates select="$sort/following-sibling::node()" mode="xst:convert">
        <xsl:with-param name="tagdefs" select="$tagdefs"/>
      </xsl:apply-templates>
    </xsl:when>
    <xsl:otherwise>
      <xsl:apply-templates select="node()" mode="xst:convert">
        <xsl:with-param name="tagdefs" select="$tagdefs"/>
      </xsl:apply-templates>
    </xsl:otherwise>
    </xsl:choose>
  </osl:for-each>
</xsl:template>

<xsl:template match="xst:for-each[fn:empty(@name)]" mode="xst:convert">
  <xsl:message terminate="yes">
    <xsl:text>xst:for-each must have a name attribute for the iterated value</xsl:text>
  </xsl:message>
</xsl:template>

<xsl:template
    match="xst:attribute|xst:choose|xst:comment|xst:element|
        xst:if|xst:namespace|xst:otherwise|xst:param|xst:processing-instruction|
        xst:text|xst:variable|xst:when"
    mode="xst:convert">
  <xsl:param name="tagdefs" as="element(xst:tag)*"/>

  <xsl:element name="xsl:{fn:local-name(.)}">
    <xsl:apply-templates select="@*" mode="xst:convert">
      <xsl:with-param name="tagdefs" select="$tagdefs"/>
    </xsl:apply-templates>
    <xsl:apply-templates select="node()" mode="xst:convert">
      <xsl:with-param name="tagdefs" select="$tagdefs"/>
    </xsl:apply-templates>
  </xsl:element>
</xsl:template>

<xsl:template match="xst:import" mode="xst:convert"/>

<xsl:template match="xst:*" mode="xst:convert">
  <xsl:message terminate="yes">
    <xsl:text>Unsupported statement: </xsl:text>
    <xsl:value-of select="fn:name(.)"/>
  </xsl:message>
</xsl:template>

<xsl:template match="@xst:*" mode="xst:convert">
  <xsl:message terminate="yes">
      <xsl:text>Unsupported attribute: </xsl:text>
      <xsl:value-of select="fn:name(.)"/>
  </xsl:message>
</xsl:template>

<xsl:template match="
      /xst:taglib/xsl:attribute-set|
      /xst:taglib/xsl:character-map|
      /xst:taglib/xsl:decimal-format|
      /xst:taglib/xsl:function|
      /xst:taglib/xsl:import|
      /xst:taglib/xsl:import-schema|
      /xst:taglib/xsl:include|
      /xst:taglib/xsl:key|
      /xst:taglib/xsl:namespace-alias|
      /xst:taglib/xsl:output|
      /xst:taglib/xsl:param|
      /xst:taglib/xsl:preserve-space|
      /xst:taglib/xsl:strip-space|
      /xst:taglib/xsl:template|
      /xst:taglib/xsl:variable"
    mode="xst:convert">
  <xsl:copy-of select="."/>
</xsl:template>

<xsl:template match="*" mode="xst:convert">
  <xsl:param name="tagdefs" as="element(xst:tag)*"/>

  <xsl:copy>
    <xsl:apply-templates select="@*" mode="xst:convert">
      <xsl:with-param name="tagdefs" select="$tagdefs"/>
    </xsl:apply-templates>
    <xsl:apply-templates select="node()" mode="xst:convert">
      <xsl:with-param name="tagdefs" select="$tagdefs"/>
    </xsl:apply-templates>
  </xsl:copy>
</xsl:template>

<xsl:template match="xst:taglib/@for"     mode="xst:convert"/>
<xsl:template match="xst:param/@implicit" mode="xst:convert"/>

<xsl:template match="@*" mode="xst:convert">
  <xsl:copy-of select="."/>
</xsl:template>

<xsl:template match="xst:text/text()" mode="xst:convert">
  <xsl:copy-of select="."/>
</xsl:template>

<xsl:template match="text()" mode="xst:convert">
  <xsl:choose>
  <xsl:when test="/xst:taglib[fn:empty(@for) or @for eq 'xstag']">
    <xsl:sequence select="xst:convert-content-expressions(.)"/>
  </xsl:when>
  <xsl:otherwise>
    <xsl:copy-of select="."/>
  </xsl:otherwise>
  </xsl:choose>
</xsl:template>

<xsl:template match="processing-instruction()" mode="xst:convert">
  <xsl:copy-of select="."/>
</xsl:template>

<xsl:template match="comment()" mode="xst:convert"/>

</xsl:stylesheet>